package com.wsc.springbootmultidevdemo.springMsg;

import com.rabbitmq.client.Channel;
import com.wsc.springbootmultidevdemo.pojo.Dog;
import com.wsc.springbootmultidevdemo.pojo.User;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
import org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.BufferedImageHttpMessageConverter;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * RabbitMq 配置
 */
@Configuration
public class RabbitConfig {

    @Bean
    public ConnectionFactory connectionFactory (){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setAddresses("127.0.0.1");
        factory.setPort(5672);
        factory.setUsername("admin");
        factory.setPassword("305617");
        factory.setVirtualHost("testhost");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){ //形参名字需要和自己注册的 ConnectionFactory 方法名相同
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        // setAutoStartup 必须设置成 true ,否则 spring 不会加载这个类
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    /**
     * 在 spring 容器中注册一个 Topic 模式的exchange
     * @return TopicExchange
     */
    @Bean
    public TopicExchange exchange(){
        return new TopicExchange("topic_exchange",true,false);
    }

    /**
     * 在 spring 容器中注册一个 queue
     *
     */
    @Bean
    public Queue topicQ(){
        return new Queue("topic_queue", true);
    }

    /**
     * 在 spring 容器中注册一个 queue
     * @return
     */
    @Bean
    public Queue topicQ1(){
        return new Queue("topic_queue1", true);
    }
    /**
     *  topicQ 与 topic exchange 绑定
     * @return
     */
    @Bean
    public Binding topicBind(){
        return BindingBuilder.bind(topicQ()).to(exchange()).with("topic.#");
    }

    /**
     * topicQ1 与 topic exchange 绑定
     * @return
     */
    @Bean
    public Binding topicBind1(){
        return BindingBuilder.bind(topicQ1()).to(exchange()).with("topic1.*");
    }

    /**
     * 在容器中注册 rabbitTemplate
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitTemplate template(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }

    /**
     * 在容器中注册一个 SimpleMessageListenerContainer
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageListener (ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer listener = new SimpleMessageListenerContainer(connectionFactory);
        //监听队列
        listener.addQueues(topicQ(),topicQ1());
        //设置消费者数量
        listener.setConcurrentConsumers(1);
        //设置最大消费者数量
        listener.setMaxConcurrentConsumers(5);
        //设置是否自动重回队列
        listener.setDefaultRequeueRejected(false);
        //设置消息 ack 模式
        listener.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //设置消费端标签策略 consumerTag
        listener.setConsumerTagStrategy(new ConsumerTagStrategy() {
            @Override
            public String createConsumerTag(String s) {
                return s+"_" + UUID.randomUUID();
            }
        });
        //设置消息监听器
        /*listener.setMessageListener(new ChannelAwareMessageListener() {
            @Override
            public void onMessage(Message message, Channel channel) throws Exception { //有消息来了就会在这个方法中监听到
                String msg = new String(message.getBody());
                System.out.println("----- 消费者 ----- "+msg);
            }
        });*/

        // --------------------------------- MessageListenerAdapter 的简单应用 -----------------------------------------

        //设置消息适配器用来监听消息
        //构造器中要传入一个自定义的消息接收器，有消息之后，适配器会将消息适配到 delegate 上
        //MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        /*//设置默认的监听方法名
        adapter.setDefaultListenerMethod("msgReceiver");
        //设置消息转化器
        adapter.setMessageConverter(new TextMessageConverter());
        //当Listener接收到消息之后，会讲消息路由给 adapter,之后 adapter 会把消息给我们自定义的 delegate
        listener.setMessageListener(adapter);*/

        // ------------------------------------ 适配器另一种方式，队列名称和方法名称匹配 -----------------------------------

        /* Map<String,String> map = new HashMap<>();
        //在 map 中添加需要绑定的队列名称和 delegate 中方法的名称
        map.put("topic_queue", "topicQ");
        map.put("topic_queue1", "topicQ1");
        //将 map 传入这个方法中
        adapter.setQueueOrTagToMethodName(map);
        //将 adapter 放入消息监听器
        listener.setMessageListener(adapter);*/

        // -------------------------------------- 各种转换器的 demo ----------------------------------------------------

        // ************ java 对象转换成 json 格式的消息转换器 *****************

        /*
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("jsonReceiver");
        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
        adapter.setMessageConverter(jsonMessageConverter);
        listener.setMessageListener(adapter);
        */

        // ************** json 对象映射成具体 java 对象的消息转换器 ******************

        /*
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("userReceiver");

        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();

        //想要支持转换成 java 对象的话就需要将 DefaultJackson2JavaTypeMapper set 进 Jackson2JsonMessageConverter
        DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();
        //注意：Springboot 2.0 版本之后要添加信任的包，不然会报错 The class '...'is not in the trusted packages
        javaTypeMapper.addTrustedPackages("com.wsc.springbootmultidevdemo.pojo");
        jsonMessageConverter.setJavaTypeMapper(javaTypeMapper);

        adapter.setMessageConverter(jsonMessageConverter);
        listener.setMessageListener(adapter);
       */

        // **************** json 映射具体 java 对象 支持 java 对象多映射转换 ******************
        // ******* 在发送消息时只需要填写在这里设置的 java 标签，而不用写具体的 reference ********

        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("userReceiver");

        Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
        DefaultJackson2JavaTypeMapper javaTypeMapper = new DefaultJackson2JavaTypeMapper();

        //设置标签和 java 类的映射
        Map<String,Class<?>> map = new HashMap<String, Class<?>>();
        map.put("user", com.wsc.springbootmultidevdemo.pojo.User.class);
        map.put("dog",com.wsc.springbootmultidevdemo.pojo.Dog.class);
        javaTypeMapper.setIdClassMapping(map);
        //设置信任的包
        javaTypeMapper.setTrustedPackages("com.wsc.springbootmultidevdemo.pojo");

        jsonMessageConverter.setJavaTypeMapper(javaTypeMapper);
        adapter.setMessageConverter(jsonMessageConverter);
        listener.setMessageListener(adapter);

        // ************************* 全局转换器，支持很多格式的转换 ****************************
/*
        MessageListenerAdapter adapter = new MessageListenerAdapter(new MessageDelegate());
        adapter.setDefaultListenerMethod("msgReceive");

        //实例化一个全局转换器
        ContentTypeDelegatingMessageConverter converter = new ContentTypeDelegatingMessageConverter();

        //实例化一个 Text 消息转换器并将该转换器放入 converter 的 delegate 设置中
        TextMessageConverter textConverter = new TextMessageConverter();
        converter.addDelegate("text", textConverter);
        converter.addDelegate("html/text", textConverter);
        converter.addDelegate("xml/text", textConverter);
        converter.addDelegate("text/plain", textConverter);

        //实例化一个 json 对象 消息转换器并将该转换器放入 converter 的 delegate 设置中
        String trustedPackages = "com.wsc.springbootmultidevdemo.pojo";
        Jackson2JsonMessageConverter jsonConverter = new Jackson2JsonMessageConverter(trustedPackages);
        converter.addDelegate("json", jsonConverter);
        converter.addDelegate("application/json", jsonConverter);

        // //实例化一个 image 消息转换器并将该转换器放入 converter 的 delegate 设置中
        ImageMessageConverter imgConverter = new ImageMessageConverter();
        converter.addDelegate("image/png", imgConverter);
        converter.addDelegate("image", imgConverter);

        //实例化一个 pdf 消息转换器并将该转换器放入 converter 的 delegate 设置中
        PDFMessageConverter pdfConverter = new PDFMessageConverter();
        converter.addDelegate("application/pdf", pdfConverter);

        adapter.setMessageConverter(converter);
        listener.setMessageListener(adapter);
        */
        return listener;
    }
}
